package com.back.security;

import com.back.common.utils.GsonUtil;
import com.back.common.utils.JwtUtil;
import com.back.common.utils.RedisUtil;
import com.back.vo.JwtVo;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * JWT认证过滤器
 * 拦截所有请求，检查JWT令牌有效性并设置Spring Security上下文
 */
@Component
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private RedisUtil redisUtil;
    
    // 不需要认证的路径
    private final List<String> excludedPaths = new ArrayList<>();
    private final AntPathMatcher pathMatcher = new AntPathMatcher();
    
    public JwtAuthenticationFilter() {
        // 添加不需要认证的路径
        excludedPaths.add("/api/auth/**");
        excludedPaths.add("/swagger-ui.html");
        excludedPaths.add("/swagger-resources/**");
        excludedPaths.add("/webjars/**");
        excludedPaths.add("/v2/**");
        excludedPaths.add("/static/**");
        excludedPaths.add("/test/**");
        excludedPaths.add("/**/favicon.ico");
        excludedPaths.add("/*/api-docs");
        excludedPaths.add("/common/job/search");
        excludedPaths.add("/common/job/**/");
        excludedPaths.add("/common/company/**");
        excludedPaths.add("/common/job/categories");
    }

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        String path = request.getServletPath();
        log.info("当前请求路径: {}", path);
        boolean shouldExclude = excludedPaths.stream()
                .anyMatch(p -> pathMatcher.match(p, path));
        log.info("是否应该排除: {}", shouldExclude);
        return shouldExclude;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        // 从请求中获取token
        String token = extractToken(request);
        
        // 处理token验证和用户认证
        if (StringUtils.isNotBlank(token)) {
            try {
                // todo 这个地方的认证相当于使用了JwtAuthenticationProvider
                if (JwtUtil.checkToken(token)) {
                    // 获取token中的用户信息
                    Claims claims = JwtUtil.getTokenBody(token);
                    JwtVo jwt = GsonUtil.fromJson(String.valueOf(claims.get("data")), JwtVo.class);
                    
                    // 检查Redis中是否存储了相同的token
                    String redisToken = redisUtil.get(String.valueOf(jwt.getId()));
                    
                    // 只有当Redis中存在且与当前token相同时才进行认证
                    if (StringUtils.isNotEmpty(redisToken) && redisToken.equals(token)) {
                        // 设置Spring Security上下文
                        authenticateUser(jwt.getName(), request);
                    }
                }
            } catch (Exception e) {
                log.error("JWT认证过程中发生错误: {}", e.getMessage());
            }
        }
        
        chain.doFilter(request, response);
    }
    
    /**
     * 从请求中提取JWT令牌
     */
    private String extractToken(HttpServletRequest request) {
        String token = request.getHeader("token");
        if (StringUtils.isBlank(token)) {
            token = request.getParameter("token");
        }
        return token;
    }
    
    /**
     * 验证用户并设置安全上下文
     */
    private void authenticateUser(String username, HttpServletRequest request) {
        if (SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            
            UsernamePasswordAuthenticationToken authentication = 
                new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            
            SecurityContextHolder.getContext().setAuthentication(authentication);
            log.info("为用户 '{}' 设置了安全上下文", username);
        }
    }
} 